package org.idea.eaglemq.broker.utils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.reflect.InvocationTargetException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;

/**
 *支持基于Java的MMap api访问文件能力（文件的读写的能力）
 *
 * 支持指定的offset的文件映射（结束映射的offset-开始映射的offset=映射的内存体积）done!
 * 文件从指定的offset开始读取 done!
 * 文件从指定的offset开始写入 done!
 * 文件映射后的内存释放 todo
 */
public class MMapUtil {

    private File file;
    private MappedByteBuffer mappedByteBuffer;
    private FileChannel fileChannel;


    /**
     * 指定offset做文件的映射
     *
     * @param filePath 文件路径
     * @param startOffset 开始映射的offset
     * @param mappedSize 映射的体积
     */
    public void loadFileInMMap(String filePath,int startOffset,int mappedSize) throws IOException {
        file = new File(filePath);
        if(!file.exists()) {
            throw new FileNotFoundException("filePath is "+filePath+" inValid");
        }
        fileChannel = new RandomAccessFile(file,"rw").getChannel();
        mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE,startOffset,mappedSize);
    }

    /**
     * 支持从文件的指定offset开始读取内容
     *
     * @param readOffset
     * @param size
     * @return
     */
    public byte[] readContent(int readOffset,int size) {
        mappedByteBuffer.position(readOffset);
        byte[] content = new byte[size];
        int j=0;
        for(int i=0;i<size;i++) {
            //这里是从内存空间读取数据
            byte b = mappedByteBuffer.get(readOffset + i);
            content[j++] = b;
        }
        return content;
    }


    /**
     * 更高性能的一种写入api
     *
     * @param content
     */
    public void writeContent(byte[] content) {
        this.writeContent(content,false);
    }

    /**
     * 写入数据到磁盘当中
     *
     * @param content
     */
    public void writeContent(byte[] content, boolean force) {
        //默认刷到page cache中，
        //如果需要强制刷盘，这里要兼容
        mappedByteBuffer.put(content);
        if(force) {
            //强制刷盘
            mappedByteBuffer.force();
        }
    }


    public void clear() {
        mappedByteBuffer.clear();
    }



    public static void main(String[] args) throws IOException, InterruptedException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        Scanner input = new Scanner(System.in);
        int i = 0;
        int size = input.nextInt();
        MMapUtil mMapUtil = new MMapUtil();
        //默认是字节
        mMapUtil.loadFileInMMap("D:\\xiangmu\\eaglemq\\broker\\store\\order_cancel_topic\\00000000", 0, 1024 * 1024 * size);
        System.out.println("映射了" + size + "m的空间");
        TimeUnit.SECONDS.sleep(5);
        System.out.println("释放内存");
        mMapUtil.clear();
        TimeUnit.SECONDS.sleep(10000);
    }

}

